﻿using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Net;
using System.Diagnostics;

namespace Utility.Net
{
    public class Web
    {
        public static DownloadContentResult DownloadContent(Uri uri, CookieCollection cookies, Dictionary<string,string> postValues, string referer,
            ProgressEventHandler progressHandler, MemoryStream memoryStream)
        {
            return DownloadContent(uri,
                cookies,
                postValues,
                referer,
                string.Empty,
                0,
                string.Empty,
                string.Empty,
                progressHandler,
                memoryStream,
                true);
        }

        public static DownloadContentResult DownloadContent(Uri uri, CookieCollection cookies, Dictionary<string,string> postValues, string referer,
            ProgressEventHandler progressHandler, MemoryStream memoryStream, bool allowRedirect)
        {
            return DownloadContent(uri,
                cookies,
                postValues,
                referer,
                string.Empty,
                0,
                string.Empty,
                string.Empty,
                progressHandler,
                memoryStream,
                allowRedirect);
        }

        public static DownloadContentResult DownloadContent(Uri uri, CookieCollection cookies, Dictionary<string,string> postValues,
            ProgressEventHandler progressHandler, MemoryStream memoryStream)
        {
            return DownloadContent(uri,
                cookies,
                postValues,
                string.Empty,
                string.Empty,
                0,
                string.Empty,
                string.Empty,
                progressHandler,
                memoryStream, 
                true);
        }

        /// <summary>
        /// Download content from the specified Uri and store in the memory stream
        /// </summary>
        /// <param name="uri"></param>
        /// <param name="progressHandler"></param>
        /// <param name="memoryStream"></param>
        public static DownloadContentResult DownloadContent(Uri uri, CookieCollection cookies, Dictionary<string,string> postValues, string referer,
            string proxyName, int port, string proxyUserName, string proxyPassword,
            ProgressEventHandler progressHandler, MemoryStream memoryStream, bool allowRedirect)
        {
            DownloadContentResult result = new DownloadContentResult();
            result.downloadCompleted = false;

            HttpWebRequest webRequest = (HttpWebRequest)HttpWebRequest.Create(uri);
            webRequest.UserAgent = "Mozilla/5.0 (Windows; U; Windows NT 6.1; pl; rv:1.9.2) Gecko/20100115 Firefox/3.9";
            webRequest.Timeout = 20000;
            webRequest.Accept = "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8";
            webRequest.KeepAlive = true;
            webRequest.Referer = referer;
            webRequest.Expect = string.Empty;
            webRequest.AllowAutoRedirect = allowRedirect;

            if ((cookies != null) && (cookies.Count > 0))
            {
                webRequest.CookieContainer = new CookieContainer(cookies.Count);
                webRequest.CookieContainer.Add(cookies);
            }

            //czy bedziemy cos wysylac?
            if (postValues != null)
            {
                
                byte[] data = PreparePostData(postValues);
                webRequest.Method = "post";

                //webRequest.ContentType = "application/x-www-form-urlencoded";
                webRequest.ContentType = "multipart/form-data; boundary=----WebKitFormBoundaryDPc7FH9Sw8O8EKFQ";
                webRequest.ContentLength = data.Length;
                Stream newStream = webRequest.GetRequestStream();
                // Send the data.
                newStream.Write(data, 0, data.Length);
                newStream.Close();
            }

            // Set proxy settings to the web request
            if (null != proxyName && proxyName.Length > 0)
            {
                webRequest.Proxy = new System.Net.WebProxy(proxyName, port);
                if (proxyUserName.Length > 0)
                {
                    // Decrypt the encrypted password
                    string password = proxyPassword;
                    // Set proxy credentials
                    webRequest.Proxy.Credentials = new System.Net.NetworkCredential(proxyUserName, password);
                }
            }



            DateTime startTime = DateTime.Now;
            try
            {
                using (System.Net.HttpWebResponse webResponse = (HttpWebResponse)webRequest.GetResponse())
                {

                    using (System.IO.Stream stream = webResponse.GetResponseStream())
                    {

                        byte[] buffer = new byte[1024 * 2]; // 2 KB buffer
                        int size;

                        while ((size = stream.Read(buffer, 0, buffer.Length)) > 0)
                        {
                            memoryStream.Write(buffer, 0, size);

                            // Perform some speed calculation
                            TimeSpan duration = DateTime.Now - startTime;	// Total time elapsed
                            double kb = (memoryStream.Length / 1024.0); // Downloaded kilobytes
                            double speed = kb / duration.TotalSeconds;
                            string message = string.Format("{0} kb, {1} kbps", kb.ToString("n2"), speed.ToString("n2"));

                            // notify download progress
                            if (progressHandler != null)
                            {
                                progressHandler(null, new ProgressEventArgs(message, 0));
                            }
                        }


                        Debug.WriteLine("\nHTTP Request  Headers :\n\n" + webRequest.Headers);
                        Debug.WriteLine("\nHTTP Response Status :\n\n" + webResponse.StatusCode.ToString() + "," + webResponse.StatusDescription);
                        Debug.WriteLine("\nHTTP Response  Headers :\n\n" + webResponse.Headers);


                        result.downloadCompleted = true;
                        //upl_frontend=rj003t0qb13joibpk4qn8g6ke2; path=/

                        if (webResponse.Headers.Get("Set-Cookie") != null)
                        {
                            result.returnedCookies = new CookieCollection();

                            string[] cookiesString = webResponse.Headers.Get("Set-Cookie").Split(';');

                            for (int i = 0; i < cookiesString.Length; i++)
                            {
                                string cookieString = cookiesString[i].Trim();
                                string[] cookieKeyAndValue = cookieString.Split('=');
                                result.returnedCookies.Add(new Cookie(cookieKeyAndValue[0], cookieKeyAndValue[1], "/", uri.Host));
                            }
                        }

                    }
                }
            }
            catch (Exception ex)
            {
                result.downloadCompleted = false;
                result.ErrorInfo = ex.Message; 
            }
            return result;
        }

        public struct DownloadContentResult
        {
            public bool downloadCompleted;
            public string ErrorInfo;
            public CookieCollection returnedCookies;

        }

        private static byte[] PreparePostData(Dictionary<string,string> postData)
        {
            StringBuilder sb = new StringBuilder();
            foreach (KeyValuePair<string, string> postElement in postData)
            {
                sb.Append("------WebKitFormBoundaryDPc7FH9Sw8O8EKFQ\r\nContent-Disposition: form-data; name=\"" + postElement.Key + "\r\n\r\n" + postElement.Value + "\r\n");
            }

            return  System.Text.Encoding.ASCII.GetBytes(sb.ToString());
        }

        public  static void DownloadRemoteFile(string uri, string fileName)
        {
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);
            HttpWebResponse response = (HttpWebResponse)request.GetResponse();

            // Check that the remote file was found. The ContentType
            // check is performed since a request for a non-existent
            // image file might be redirected to a 404-page, which would
            // yield the StatusCode "OK", even though the image was not
            // found.
            if ((response.StatusCode == HttpStatusCode.OK ||
                response.StatusCode == HttpStatusCode.Moved ||
                response.StatusCode == HttpStatusCode.Redirect))
            {

                // if the remote file was found, download oit
                using (Stream inputStream = response.GetResponseStream())
                using (Stream outputStream = File.OpenWrite(fileName))
                {
                    byte[] buffer = new byte[4096];
                    int bytesRead;
                    do
                    {
                        bytesRead = inputStream.Read(buffer, 0, buffer.Length);
                        outputStream.Write(buffer, 0, bytesRead);
                    } while (bytesRead != 0);
                }
            }
        }
    }


    public delegate void ProgressEventHandler(object sender, ProgressEventArgs e);
    /// <summary>
    /// Event argument for progress messages
    /// </summary>
    [Serializable]
    public class ProgressEventArgs : EventArgs
    {
        public string Message;
        public int Value;
        public ProgressEventArgs(string message, int value)
        {
            this.Message = message;
            this.Value = value;
        }
    }
}
